//////////////////////////////////////////////////////////////////////////////////
//	 Copyright 2011 by Yosef Grabivker, ryuho@homenetworksoft.com
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//////////////////////////////////////////////////////////////////////////////////

#include <wx/wx.h>
#include <wx/statline.h>
#include "syslogoptions.h"

enum cIDS
{
	cIDBrowseButton=7777,
	cIDSaveLogSel,
	cIDLogAutoConfSel,
	cIDTextTemplBase=8000,
	cIDComboBase=8100

};

BEGIN_EVENT_TABLE(CSysLogOptions, wxPanel)
	EVT_BUTTON(cIDBrowseButton, CSysLogOptions::OnSelectLogFileName)
	EVT_CHECKBOX(cIDSaveLogSel, CSysLogOptions::OnTogleLogSaving)
	EVT_CHECKBOX(cIDLogAutoConfSel, CSysLogOptions::OnTogleAutoConfig)
	EVT_COMMAND_RANGE(cIDTextTemplBase, cIDTextTemplBase+10, wxEVT_COMMAND_TEXT_UPDATED, CSysLogOptions::OnTemplateUpdated)
	EVT_COMMAND_RANGE(cIDComboBase, cIDComboBase+10, wxEVT_COMMAND_TEXT_UPDATED, CSysLogOptions::OnActionUpdated) 
END_EVENT_TABLE()


CSysLogOptions::CSysLogOptions(wxWindow* pParent):wxPanel(pParent)
{
	int nFlags      = wxLEFT|wxUP|wxRIGHT|wxALIGN_CENTRE_VERTICAL;
	int nFlagsSave  = wxRIGHT|wxALIGN_CENTRE_VERTICAL;
	int nBorder		= 5;

	wxBoxSizer* pSizer = new wxBoxSizer(wxVERTICAL);


	wxBoxSizer* pSzPortNumber = new wxBoxSizer(wxHORIZONTAL);
	wxStaticText* pTxtPortB = new wxStaticText(this, wxID_ANY, _("Syslog port number:"));
	pSzPortNumber->Add( pTxtPortB, 0, wxLEFT|wxUP|wxALIGN_CENTRE_VERTICAL, nBorder);

	m_pSyslogPort  = new wxTextCtrl(this, wxID_ANY, m_strSysLogPort,
		wxDefaultPosition, wxSize(50,20), 0, wxTextValidator(wxFILTER_NUMERIC, &m_strSysLogPort));

	pSzPortNumber->Add( m_pSyslogPort, 0, nFlags, nBorder);
	pSizer->Add( pSzPortNumber, 0, wxLEFT,nBorder );

	m_pcbLogFromRouter = new wxCheckBox(this, wxID_ANY, _("Receive from router only") );
	m_pcbLogMACBlocks  = new wxCheckBox(this, wxID_ANY, _("Log access attempts from blocked MAC addresses") );

	pSizer->Add(m_pcbLogFromRouter, 0, wxLEFT|wxUP|wxRIGHT,10);
	pSizer->Add(m_pcbLogMACBlocks,  0, wxLEFT|wxUP|wxRIGHT,10);

	//Save log file options
	m_pLogFileSizer = new wxBoxSizer(wxHORIZONTAL);
	{
		m_pcbSaveLog = new wxCheckBox(this, cIDSaveLogSel, wxT(""));
		m_pLogFileSizer->Add(m_pcbSaveLog, 0, nFlagsSave, nBorder );

		wxStaticText* pTxt = new wxStaticText(this, wxID_ANY, _("Save to:"));
		m_pLogFileSizer->Add(pTxt, 0, nFlagsSave, nBorder );

		m_ptcDirName = new wxTextCtrl(this, wxID_ANY,wxT(""), wxDefaultPosition, wxSize(100, wxDefaultSize.GetY()));
		m_pLogFileSizer->Add(m_ptcDirName, 0, nFlagsSave, nBorder);

		wxButton* pBtn = new wxButton(this, cIDBrowseButton, _T("..."), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT|wxNO_BORDER );
		m_pLogFileSizer->Add(pBtn, 0, nFlagsSave, nBorder);

		pTxt = new wxStaticText(this, wxID_ANY, _("Size Limit(Mbyte):"));
		m_pLogFileSizer->Add(pTxt, 0, nFlagsSave, nBorder );

		wxArrayString choices;
		choices.Add(wxT("Unlimited"));
		choices.Add(wxT("1"));
		choices.Add(wxT("10"));
		choices.Add(wxT("50"));
		choices.Add(wxT("100"));
		choices.Add(wxT("200"));
		choices.Add(wxT("300"));
		choices.Add(wxT("400"));
		choices.Add(wxT("500"));
		choices.Add(wxT("600"));
		choices.Add(wxT("700"));
		choices.Add(wxT("800"));
		choices.Add(wxT("900"));
		choices.Add(wxT("1024"));
		
		m_pLimitSelector = new wxComboBox(this, wxID_ANY, wxT("Unlimited"), wxDefaultPosition, wxSize(100, wxDefaultSize.GetY()), choices, wxCB_DROPDOWN|wxCB_READONLY );
		m_pLogFileSizer->Add(m_pLimitSelector, 0, nFlagsSave, nBorder );
	}
	pSizer->Add(m_pLogFileSizer,  0, wxLEFT|wxUP|wxRIGHT,10);

	//Syslogd
	m_pSyslogAutoConfigSizer = new wxBoxSizer(wxHORIZONTAL);
	{
		m_pcbSyslogAutoConfig = new wxCheckBox(this, cIDLogAutoConfSel, _("Auto-configuration"));
		m_pSyslogAutoConfigSizer->Add(m_pcbSyslogAutoConfig, 0, nFlagsSave, nBorder );

		wxStaticText* pTxt = new wxStaticText(this, wxID_ANY, _("Log Level:"));
		m_pSyslogAutoConfigSizer->Add(pTxt, 0, wxLEFT|wxRIGHT|wxALIGN_CENTRE_VERTICAL, nBorder );

		m_pSysLogLevelSelector = new wxComboBox(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(100, wxDefaultSize.GetY()), 0, NULL, wxCB_DROPDOWN|wxCB_READONLY );
		m_pSyslogAutoConfigSizer->Add(m_pSysLogLevelSelector, 0, nFlagsSave, nBorder );

		m_pSysLogLevelSelector->Append( _("Emergency"),		(void*)0);
		m_pSysLogLevelSelector->Append( _("Alert"),			(void*)1);
		m_pSysLogLevelSelector->Append( _("Critical"),		(void*)2);
		m_pSysLogLevelSelector->Append( _("Error"),			(void*)3);
		m_pSysLogLevelSelector->Append( _("Warning"),		(void*)4);
		m_pSysLogLevelSelector->Append( _("Notice"),		(void*)5);
		m_pSysLogLevelSelector->Append( _("Informational"),	(void*)6);
		m_pSysLogLevelSelector->Append( _("Debugging"),		(void*)7);
	}
	pSizer->Add(m_pSyslogAutoConfigSizer,  0, wxLEFT|wxUP|wxRIGHT,10);

	///////////////////////////////////////////////////////////////////////////////////////////
	//Line
	pSizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxSize(10,2), wxLI_HORIZONTAL), 0, wxALL|wxEXPAND, 10);

	m_ppMsgTemplate = new  wxTextCtrl*[MAX_SYSLOG_RULES];
	m_ppReaction	= new  wxComboBox*[MAX_SYSLOG_RULES];

	for (int i=0;i<MAX_SYSLOG_RULES;i++)
	{
		wxBoxSizer* pSizeRule = new wxBoxSizer(wxHORIZONTAL);
		wxStaticText* pTxt = new wxStaticText(this, wxID_ANY, _("On Syslog Message:"));
		pSizeRule->Add(pTxt, 0, nFlags, nBorder );

		m_ppMsgTemplate[i] = new wxTextCtrl(this, cIDTextTemplBase+i, wxT(""),
			wxDefaultPosition, wxSize(150, wxDefaultSize.GetY()));
		pSizeRule->Add(m_ppMsgTemplate[i], 0, nFlags, nBorder);

		pSizeRule->Add(new wxStaticText(this, wxID_ANY, _("do:")), 0, nFlags, nBorder );

		m_ppReaction[i]	= new wxComboBox(this, 	cIDComboBase+i, _("Nothing"), wxDefaultPosition, wxSize(100, wxDefaultSize.GetY()), 0, NULL, wxCB_DROPDOWN|wxCB_READONLY );
		pSizeRule->Add(m_ppReaction[i], 0, nFlags, nBorder);

		m_ppReaction[i]->Append ( _("Nothing"), (void*)cRCACTNothing);
		m_ppReaction[i]->Append ( _("Reboot"), (void*)cRCACTReboot);
		m_ppReaction[i]->Append ( _("Run"), (void*)cRCACTScript);
		m_ppReaction[i]->Select(0);
		m_ppReaction[i]->Enable(false);

		pSizer->Add(pSizeRule,0, wxALIGN_CENTRE_HORIZONTAL,0);
	}

	SetSizer(pSizer);
}

CSysLogOptions::~CSysLogOptions(void)
{
}



void CSysLogOptions::SetSysLogActions(const SYSLOGACTIONS& act)
{
	m_actions = act;

	for(SYSLOGACTIONS::const_iterator iCur = act.begin();
		iCur != act.end();iCur++)
	{
		const SYSLOGACTION& action = iCur->second;
		unsigned char nIDX = iCur->first;

		if ( nIDX<MAX_SYSLOG_RULES )
		{
			m_ppMsgTemplate[nIDX]->SetValue( action.strPattern );

			for (unsigned int i=0;i< m_ppReaction[nIDX]->GetCount();i++)
			{
				void *p = m_ppReaction[nIDX]->GetClientData(i);

				if ( (int)p==action.recvStrat )
				{
					wxString strLabel;

					switch(action.recvStrat)
					{
						case cRCACTNothing:
							strLabel = _("Nothing"); 
						break;

						case cRCACTReboot:
							strLabel = _("Reboot"); 
						break;

						case cRCACTScript:
							if (action.strScriptName.empty())
							{
								strLabel = _("Run");
							}
							else
							{
								strLabel = action.strScriptName;
							}
						break;
					}

					m_ppReaction[nIDX]->SetString(i, strLabel);
					m_ppReaction[nIDX]->Select(i);
					break;
				}
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////////////
//Logic
void CSysLogOptions::GetAction(unsigned char nIDX, SYSLOGACTION& action)
{
	SYSLOGACTIONS::iterator iCur = m_actions.find(nIDX);

	if ( iCur!=m_actions.end() )
	{
		action = iCur->second;
	}
	else //default
	{
		action.recvStrat = cRCACTNothing;
		action.strPattern= wxT("");
	}
}

void CSysLogOptions::SetAction(unsigned char nIDX, const SYSLOGACTION& action)
{
	m_actions[nIDX] = action;
}

void CSysLogOptions::SetEnableSyslogSave( bool bSet )
{
	m_pcbSaveLog->SetValue(bSet);
	wxCommandEvent event;
	OnTogleLogSaving(event);
}

bool CSysLogOptions::GetEnableSyslogSave()
{
	return m_pcbSaveLog->GetValue();
}

void CSysLogOptions::SetSyslogSaveFileName( const wxString& str )
{
	m_ptcDirName->SetValue(str);
}

wxString CSysLogOptions::GetSyslogSaveFileName()
{
	return m_ptcDirName->GetValue();
}

void CSysLogOptions::SetSysLogUDPPort(long lVal )
{
	m_strSysLogPort = wxString::Format(wxT("%d"), lVal);

	m_pSyslogPort->SetValue(  m_strSysLogPort );
}

long CSysLogOptions::GetSysLogUDPPort()
{
	long lPort= atol( m_pSyslogPort->GetValue().ToAscii());

	return lPort?lPort:DEF_SYSLOG_PORT;
}

void CSysLogOptions::SetSyslogSaveLimit( long lLimit )
{
	wxString strVal;

	for ( size_t i=0;i<m_pLimitSelector->GetCount();i++ )
	{
		strVal = m_pLimitSelector->GetString( i );
		
		if ( lLimit == atol ( strVal.ToAscii() ) )
		{
			m_pLimitSelector->SetSelection( i );
			break;
		}
	}
}

long CSysLogOptions::GetSyslogSaveLimit()
{
	wxString strVal = m_pLimitSelector->GetValue();
	return atol ( strVal.ToAscii() );
}

void CSysLogOptions::SetEnableSyslogAutoConfig( bool bSet )
{
	m_pcbSyslogAutoConfig->SetValue(bSet);
	wxCommandEvent event;
	OnTogleAutoConfig(event);
}

bool CSysLogOptions::GetEnableSyslogAutoConfig()
{
	return m_pcbSyslogAutoConfig->GetValue();
}

void CSysLogOptions::SetSyslogAutoConfigLevel(long lLimit)
{
	void* pData;
	
	for ( size_t i=0;i<m_pSysLogLevelSelector->GetCount();i++ )
	{
		pData = m_pSysLogLevelSelector->GetClientData( i );
		
		if ( lLimit == (long)pData )
		{
			m_pSysLogLevelSelector->SetSelection( i );
			break;
		}
	}
}

long CSysLogOptions::GetSyslogAutoConfigLevel()
{
	void* pData = m_pSysLogLevelSelector->GetClientData( m_pSysLogLevelSelector->GetCurrentSelection());

	return (long)pData;
}


//////////////////////////////////////////////////////////////////////////////////
//Events
void CSysLogOptions::OnSelectLogFileName(wxCommandEvent& event)
{
	try
	{
		 wxDirDialog dlg(this, _("Choose directory to save log files"),
				wxT(""), wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );

		if ( wxID_OK ==dlg.ShowModal() )
		{
			m_ptcDirName->SetValue(dlg.GetPath());
		}
	}
	catch(...)
	{
		wxMessageBox(_("Failed!"), _("Error"), wxICON_WARNING | wxOK, this);
	}
}

void CSysLogOptions::OnTogleLogSaving(wxCommandEvent& event)
{
	wxSizerItemList list = m_pLogFileSizer->GetChildren();

	wxSizerItemList::iterator iter;
    for (iter = list.begin(); iter != list.end(); ++iter)
    {
       wxSizerItem *pItem = *iter;

	   if ( pItem && pItem->GetWindow()!=m_pcbSaveLog )
	   {
		   pItem->GetWindow()->Enable(m_pcbSaveLog->GetValue());
	   }
	}
}

void CSysLogOptions::OnTogleAutoConfig(wxCommandEvent& event)
{
	wxSizerItemList list = m_pSyslogAutoConfigSizer->GetChildren();

	wxSizerItemList::iterator iter;
    for (iter = list.begin(); iter != list.end(); ++iter)
    {
       wxSizerItem *pItem = *iter;

	   if ( pItem && pItem->GetWindow()!=m_pcbSyslogAutoConfig )
	   {
		   pItem->GetWindow()->Enable(m_pcbSyslogAutoConfig->GetValue());
	   }
	}
}


void CSysLogOptions::OnTemplateUpdated(wxCommandEvent& ev)
{
	int nIDX = ev.GetId() - cIDTextTemplBase;
	wxString strVal = m_ppMsgTemplate[nIDX]->GetValue();

	strVal = strVal.Trim();
	strVal = strVal.Trim(false);

	m_ppReaction[nIDX]->Enable( !strVal.IsEmpty() );

	SYSLOGACTION action;
	GetAction((unsigned char)nIDX, action);

	action.strPattern = strVal;
	SetAction((unsigned char)nIDX, action);
}

void CSysLogOptions::OnActionUpdated(wxCommandEvent& ev)
{
	int nIDX = ev.GetId() - cIDComboBase;
	int nSel = m_ppReaction[nIDX]->GetSelection();

	if ( wxNOT_FOUND!=nSel )
	{
		void* p = m_ppReaction[nIDX]->GetClientData(nSel);
		cRecoveryStrategy	recvStrat = (cRecoveryStrategy)(int)p;

		SYSLOGACTION action;
		GetAction((unsigned char)nIDX, action);
		action.recvStrat = recvStrat;

		if ( cRCACTScript==action.recvStrat )
		{
			try
			{
				wxFileDialog dlg(this, _("Choose a file to Run"), wxT(""), wxT(""), wxT("*.*"), wxFD_OPEN );

				if ( wxID_OK ==dlg.ShowModal() )
				{
					action.strScriptName = dlg.GetPath();
					SetAction((unsigned char)nIDX, action);
					SetSysLogActions( m_actions );
				}
			}
			catch(...)
			{
				wxMessageBox(_("Failed!"), _("Error"), wxICON_WARNING | wxOK, this);
			}
		}
		else
		{
			SetAction((unsigned char)nIDX, action);
		}
	}
}
